package com.zx.idc.backend.gui.api.management.basicdata;

import com.zx.idc.backend.gui.api.management.basicdata.report.IdcBasicDataUtil;
import com.zx.idc.ds.base.cus.entity.BaseCustomer;
import com.zx.idc.ds.base.cus.service.IBaseCustomerService;
import com.zx.idc.ds.base.cus.service.IBaseServiceInfoService;
import com.zx.idc.ds.base.house.entity.*;
import com.zx.idc.ds.base.house.service.*;
import com.zx.idc.ds.base.ip.entity.BaseIpAddressInfo;
import com.zx.idc.ds.base.ip.service.IBaseIpAddressInfoService;
import com.zx.idc.ds.base.oper.entity.BaseOperCompany;
import com.zx.idc.ds.base.oper.service.IBaseOperCompanyService;
import com.zx.idc.ds.base.serve.entity.BaseServiceDomain;
import com.zx.idc.ds.base.serve.service.IBaseServiceDomainService;
import com.zx.idc.ds.base.server.service.IBaseServerInfoService;
import com.zx.idc.ds.common.constant.DataFeatureConstant;
import com.zx.idc.ds.common.constant.ReportStatusConstant;
import com.zx.idc.xml.entity.basedata.BasicInfo;
import com.zx.idc.xml.entity.basedata.UpdateInfo;
import com.zx.idc.xml.entity.basedata.basic.EmergencyContact;
import com.zx.idc.xml.entity.basedata.basic.HouseInfo;
import com.zx.idc.xml.entity.basedata.basic.IdcOfficer;
import com.zx.idc.xml.entity.basedata.basic.UserInfo;
import com.zx.idc.xml.entity.basedata.basic.houseinfo.GatewayInfo;
import com.zx.idc.xml.entity.basedata.basic.houseinfo.HouseOfficer;
import com.zx.idc.xml.entity.basedata.basic.houseinfo.IpSegInfo;
import com.zx.idc.xml.entity.basedata.basic.userinfo.HouseHoldInfo;
import com.zx.idc.xml.entity.basedata.basic.userinfo.HousesHoldInfo;
import com.zx.idc.xml.entity.basedata.basic.userinfo.ServiceInfo;
import com.zx.idc.xml.entity.basedata.delete.DeleteInfo;
import com.zx.idc.xml.entity.basedata.delete.House;
import io.vavr.Tuple;
import io.vavr.control.Option;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * @author rxliuli
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class BaseIdcBasicDataService {

    @Autowired
    protected IBaseOperCompanyService baseOperCompanyService;
    @Autowired
    protected IBaseHouseInfoService baseHouseInfoService;
    @Autowired
    protected IBaseCustomerService baseCustomerService;
    @Autowired
    protected IBaseHouseOfficerService baseHouseOfficerService;
    @Autowired
    protected IBaseHouseLinkInfoService baseHouseLinkInfoService;
    @Autowired
    protected IBaseIpAddressInfoService baseIpAddressInfoService;
    @Autowired
    protected IBaseIdcHouseAreaService baseIdcHouseAreaService;
    @Autowired
    protected IBaseFrameInfoService baseFrameInfoService;
    @Autowired
    protected IBaseHousesHoldInfoService baseHousesHoldInfoService;
    @Autowired
    protected IBaseIpTransInfoService baseIpTransInfoService;
    @Autowired
    protected IBaseServerInfoService baseServerInfoService;
    @Autowired
    protected IBaseServiceDomainService baseServiceDomainService;
    @Autowired
    protected IdcBasicDataUtil idcBasicDataUtil;
    @Autowired
    private IBaseServiceInfoService baseServiceInfoService;

    public Map<Long, BaseHouseOfficer> queryBaseCustomerHouseOfficerMap(List<BaseCustomer> baseCustomerList) {
        return baseHouseOfficerService.selectBatchIds(baseCustomerList.stream()
            .map(BaseCustomer::getOfficer)
            .collect(Collectors.toList())).stream().collect(Collectors.toMap(BaseHouseOfficer::getId, e -> e));
    }

    public List<BaseIpTransInfo> queryBaseIpTransInfoList(List<BaseHousesHoldInfo> baseHousesHoldInfoList) {
        return baseIpTransInfoService.listBatchByEntityList(baseHousesHoldInfoList.stream()
            .map(bhhi -> new BaseIpTransInfo().setHoldId(bhhi.getId()))
            .collect(Collectors.toList()));
    }

    public List<BaseFrameInfo> queryBaseFrameInfoList(List<BaseIdcHouseArea> baseIdcHouseAreaList) {
        return baseFrameInfoService.listBatchByEntityList(baseIdcHouseAreaList.stream()
            .map(baseIdcHouseArea -> new BaseFrameInfo().setHouseArea(baseIdcHouseArea.getId()))
            .collect(Collectors.toList()));
    }

    public List<BaseIdcHouseArea> queryBaseIdcHouseAreaList(List<BaseHouseInfo> baseHouseInfoList) {
        return baseIdcHouseAreaService.listBatchByEntityList(baseHouseInfoList.stream()
            .map(bhi -> new BaseIdcHouseArea().setHouseId(bhi.getId()))
            .collect(Collectors.toList()));
    }

    public List<BaseIpAddressInfo> queryBaseIpAddressInfoList(List<BaseHouseInfo> baseHouseInfoList) {
        return baseIpAddressInfoService.listBatchByEntityList(baseHouseInfoList.stream()
            .map(bhi -> new BaseIpAddressInfo().setHouseId(bhi.getId()))
            .collect(Collectors.toList()));
    }

    public List<BaseHouseLinkInfo> queryBaseHouseLinkInfoList(List<BaseHouseInfo> baseHouseInfoList) {
        return baseHouseLinkInfoService.listBatchByEntityList(baseHouseInfoList.stream()
            .map(bhi -> new BaseHouseLinkInfo().setHouseId(bhi.getId()))
            .collect(Collectors.toList()));
    }

    public Map<Long, BaseHouseOfficer> queryBaseHouseOfficerMap(List<BaseHouseInfo> baseHouseInfoList) {
        return baseHouseOfficerService.selectBatchIds(baseHouseInfoList.stream()
            .map(BaseHouseInfo::getHouseOfficer)
            .collect(Collectors.toList())).stream().collect(Collectors.toMap(BaseHouseOfficer::getId, e -> e));
    }

    public void update(BasicInfo basicInfo, int reported) {
        // region 通用的后续处理操作
        final Consumer<String> companyProcessor = en -> Option.of(en)
            .map(idcId -> new BaseOperCompany()
                .setIdcId(idcId)
                .setReportStatus(reported)
            )
            .filter(Objects::nonNull)
            .peek(baseOperCompanyService::updateIgnoreDelFlag);
        Consumer<Option<String>> officerProcessor = s ->
            s.filter(NumberUtils::isCreatable)
                .map(id -> new BaseHouseOfficer()
                    .setId(Long.parseLong(id))
                    .setReportStatus(reported))
                .peek(baseHouseOfficerService::updateIgnoreDelFlag);
        final Consumer<EmergencyContact> emergencyContactProcessor = en -> Option.of(en)
            .map(EmergencyContact::getId)
            .map(Option::of)
            .peek(officerProcessor);
        final Consumer<IdcOfficer> idcOfficerProcessor = en -> Option.of(en)
            .map(IdcOfficer::getId)
            .map(Option::of)
            .peek(officerProcessor);
        final Consumer<HouseOfficer> houseOfficerProcessor = en -> Option.of(en)
            .map(HouseOfficer::getId)
            .map(Option::of)
            .peek(officerProcessor);
        final Consumer<List<IpSegInfo>> ipSegInfoProcessor = en -> Option.of(en)
            .map(ipSegInfos -> ipSegInfos.stream().map(IpSegInfo::getId))
            .map(stream -> stream.map(id -> new BaseIpAddressInfo()
                .setId(id)
                .setReportStatus(reported)
            ).collect(Collectors.toList()))
            .peek(baseIpAddressInfoService::updateBatchIgnoreDelFlag);
        final Consumer<List<GatewayInfo>> gatewayInfoProcessor = en -> Option.of(en)
            .map(ipSegInfos -> ipSegInfos.stream().map(GatewayInfo::getId))
            .map(stream -> stream.map(id -> new BaseHouseLinkInfo()
                .setId(id)
                .setReportStatus(reported)
            ).collect(Collectors.toList()))
            .peek(baseHouseLinkInfoService::updateBatchIgnoreDelFlag);
        final Consumer<List<HouseInfo>> houseInfoProcessor = houseInfo -> Option.of(houseInfo)
            .map(houseInfos -> {
                houseInfos.forEach(hi -> {
                    houseOfficerProcessor.accept(hi.getHouseOfficer());
                    gatewayInfoProcessor.accept(hi.getGatewayInfo());
                    ipSegInfoProcessor.accept(hi.getIpSegInfo());
                });
                return houseInfos.stream().map(HouseInfo::getHouseId);
            })
            .map(stream -> stream.map(id -> new BaseHouseInfo()
                .setId(id)
                .setReportStatus(reported)
            ).collect(Collectors.toList()))
            .peek(baseHouseInfoService::updateBatchIgnoreDelFlag);
        final Consumer<List<ServiceInfo>> serviceInfoProcessor = en -> Option.of(en)
            .map(serviceInfos -> serviceInfos.stream().map(ServiceInfo::getServiceId))
            .map(stream -> stream.map(id -> {
                baseServiceDomainService.updateIgnoreDelFlagByServiceId(new BaseServiceDomain().setServiceId(id).setReportStatus(reported));
                return new BaseServiceInfo()
                    .setId(id)
                    .setReportStatus(reported);
            }).collect(Collectors.toList()))
            .peek(baseServiceInfoService::updateBatchIgnoreDelFlag);
        final Consumer<List<HousesHoldInfo>> housesHoldInfoProcessor = en -> Option.of(en)
            .map(housesHoldInfos -> housesHoldInfos.stream().map(HousesHoldInfo::getHhId))
            .map(stream -> stream.map(id -> new BaseHousesHoldInfo()
                .setId(id)
                .setReportStatus(reported)
            ).collect(Collectors.toList()))
            .peek(baseHousesHoldInfoService::updateBatchIgnoreDelFlag);
        final Consumer<List<HouseHoldInfo>> houseHoldInfoProcessor = en -> Option.of(en)
            .map(housesHoldInfos -> housesHoldInfos.stream().map(HouseHoldInfo::getHhId))
            .map(stream -> stream.map(id -> new BaseHousesHoldInfo()
                .setId(id)
                .setReportStatus(reported)
            ).collect(Collectors.toList()))
            .peek(baseHousesHoldInfoService::updateBatchIgnoreDelFlag);
        final Consumer<List<UserInfo>> userInfoProcessor = en -> Option.of(en)
            .map(userInfos -> {
                userInfos.forEach(ui -> {
                    serviceInfoProcessor.accept(ui.getInfo().getServiceInfo());
                    houseHoldInfoProcessor.accept(ui.getInfo().getHouseHoldInfo());
                    ui.getInfo().getServiceInfo().forEach(serviceInfo -> housesHoldInfoProcessor.accept(serviceInfo.getHousesHoldInfo()));
                });
                return userInfos.stream().map(UserInfo::getId);
            })
            .map(stream -> stream.map(id -> new BaseCustomer()
                .setId(id)
                .setReportStatus(reported)
            ).collect(Collectors.toList()))
            .peek(baseCustomerService::updateBatchIgnoreDelFlag);
        // endregion

        // region 更新新增信息
        Option.of(basicInfo)
            .map(BasicInfo::getNewInfo)
            .filter(Objects::nonNull)
            .peek(newInfo -> {
                BaseOperCompany baseOperCompany = baseOperCompanyService.selectOne(new BaseOperCompany().setIdcId(newInfo.getIdcId()));
                if (baseOperCompany.getReportStatus() == ReportStatusConstant.REPORTING && baseOperCompany.getDataFeature() == DataFeatureConstant.NEW) {
                    companyProcessor.accept(newInfo.getIdcId());
                }

            })
            .peek(newInfo -> emergencyContactProcessor.accept(newInfo.getEmergencyContact()))
            .peek(newInfo -> idcOfficerProcessor.accept(newInfo.getIdcOfficer()))
            .peek(newInfo -> houseInfoProcessor.accept(newInfo.getHouseInfo()))
            .peek(newInfo -> userInfoProcessor.accept(newInfo.getUserInfo()));

        //endregion

        // region 更新修改信息
        Option.of(basicInfo)
            .map(BasicInfo::getUpdateInfo)
            .filter(Objects::nonNull)
            .peek(updateInfo -> {
                BaseOperCompany baseOperCompany = baseOperCompanyService.selectOne(new BaseOperCompany().setIdcId(updateInfo.getIdcId()));
                if (baseOperCompany.getReportStatus() == ReportStatusConstant.REPORTING && baseOperCompany.getDataFeature() == DataFeatureConstant.UPDATE) {
                    companyProcessor.accept(updateInfo.getIdcId());
                }
            })
            .peek(updateInfo -> emergencyContactProcessor.accept(updateInfo.getEmergencyContact()))
            .peek(updateInfo -> idcOfficerProcessor.accept(updateInfo.getIdcOfficer()))
            .map(UpdateInfo::getUpdateData)
            .filter(Objects::nonNull)
            .peek(updateData -> houseInfoProcessor.accept(updateData.getHouseInfo()))
            .peek(updateData -> userInfoProcessor.accept(updateData.getUserInfo()));
        // endregion

        // region 更新删除信息
        Option.of(basicInfo)
            .map(BasicInfo::getDeleteInfo)
            .filter(Objects::nonNull)
            .peek(deleteInfo -> {
                BaseOperCompany baseOperCompany = baseOperCompanyService.selectListForDelReport(new BaseOperCompany().setIdcId(deleteInfo.getIdcId())).get(0);
                if (baseOperCompany.getReportStatus() == ReportStatusConstant.REPORTING && baseOperCompany.getDataFeature() == DataFeatureConstant.DELETE) {
                    companyProcessor.accept(deleteInfo.getIdcId());
                }
            })
            .map(DeleteInfo::getDeleteData)
            .filter(Objects::nonNull)
            .peek(deleteData -> Option.of(deleteData.getHouse())
                .filter(Objects::nonNull)
                .map(houses -> {
                    houses.forEach(house -> {
                        if (house.getGatewayId() == null && house.getIpSegId() == null) {
                            baseHouseInfoService.updateIgnoreDelFlag(new BaseHouseInfo().setId(house.getHouseId()).setReportStatus(reported));
                            baseHouseLinkInfoService.updateIgnoreDelFlag(new BaseHouseLinkInfo().setHouseId(house.getHouseId()).setReportStatus(reported));
                            baseIpAddressInfoService.updateIgnoreDelFlag(new BaseIpAddressInfo().setHouseId(house.getHouseId()).setReportStatus(reported));
                        }
                    });
                    final List<BaseHouseLinkInfo> houseLinkInfoList = houses.stream().filter(house -> house.getGatewayId() != null)
                        .map(House::getGatewayId).map(id -> new BaseHouseLinkInfo().setId(id).setReportStatus(reported)).collect(Collectors.toList());
                    final List<BaseIpAddressInfo> ipAddressList = houses.stream().filter(house -> house.getIpSegId() != null)
                        .map(House::getIpSegId).map(id -> new BaseIpAddressInfo().setId(id).setReportStatus(reported)).collect(Collectors.toList());
                    return Tuple.of(houseLinkInfoList, ipAddressList);
                })
                .peek(tuple -> {
                    tuple._1.forEach(en -> baseHouseLinkInfoService.updateIgnoreDelFlag(en));
                    tuple._2.forEach(en -> baseIpAddressInfoService.updateIgnoreDelFlag(en));
                }))
            .map(deleteData -> {
                Option.of(deleteData.getUser())
                    .filter(Objects::nonNull)
                    .forEach(users -> {
                        users.forEach(user -> {
                            if (user.getService().size() == 0 && user.getHhId() == null) {
                                baseCustomerService.updateIgnoreDelFlag(new BaseCustomer().setId(user.getUserId()).setReportStatus(reported));
                                baseHousesHoldInfoService.updateIgnoreDelFlag(new BaseHousesHoldInfo().setCustomerId(user.getUserId()).setReportStatus(reported));
                                baseServiceInfoService.updateIgnoreDelFlag(new BaseServiceInfo().setCustomerId(user.getUserId()).setReportStatus(reported));
                                baseServiceInfoService.selectListForDelReport(new BaseServiceInfo().setCustomerId(user.getUserId()))
                                    .forEach(baseServiceInfo -> baseServiceDomainService.updateIgnoreDelFlag(new BaseServiceDomain().setServiceId(baseServiceInfo.getId()).setReportStatus(reported)));
                            } else if (user.getHhId() != null) {
                                baseHousesHoldInfoService.updateIgnoreDelFlag(new BaseHousesHoldInfo().setId(user.getHhId()).setReportStatus(reported));
                            } else {
                                user.getService().forEach(service -> {
                                    if (service.getDomainId().size() == 0 && service.getHhId() == null) {
                                        baseServiceInfoService.updateIgnoreDelFlag(new BaseServiceInfo().setId(service.getServiceId()).setReportStatus(reported));
                                        baseServiceInfoService.selectListForDelReport(new BaseServiceInfo().setId(service.getServiceId()))
                                            .forEach(baseServiceInfo -> {
                                                baseServiceDomainService.updateIgnoreDelFlag(new BaseServiceDomain().setServiceId(baseServiceInfo.getId()).setReportStatus(reported));
                                                baseHousesHoldInfoService.updateIgnoreDelFlag(new BaseHousesHoldInfo().setId(baseServiceInfo.getHoldId()).setReportStatus(reported));
                                            });
                                    } else if (service.getDomainId().size() > 0) {
                                        service.getDomainId().forEach(domainId -> {
                                            baseServiceDomainService.updateIgnoreDelFlag(new BaseServiceDomain().setId(domainId).setReportStatus(reported));
                                        });
                                    }
                                });
                            }
                        });
                    });
                return deleteData;
            });
        // endregion

        // region 查询结果更新

        Option.of(basicInfo)
            .map(BasicInfo::getQueryResult)
            .filter(Objects::nonNull)
            .peek(queryResult -> companyProcessor.accept(queryResult.getIdcId()))
            .peek(queryResult -> emergencyContactProcessor.accept(queryResult.getEmergencyContact()))
            .peek(queryResult -> idcOfficerProcessor.accept(queryResult.getIdcOfficer()))
            .peek(queryResult -> houseInfoProcessor.accept(queryResult.getHouseInfo()))
            .peek(queryResult -> userInfoProcessor.accept(queryResult.getUserInfo()));

        // endregion
    }
}
